/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Printing;
using System.Text;
using System.Globalization;
using System.Threading.Tasks;
using System.Data.Objects;
#if _LOCALDB
  using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif
namespace Oceanside
{
    [Serializable]
    public class PrintObject
    {
        public PrintObject(Int64 pId)
        {
            printerGroupingId = pId;
        }

        Int64 printerGroupingId;
        public Int64 PrinterGroupingId
        {
            get { return printerGroupingId; }
            set { printerGroupingId = value; }
        }

        StringBuilder receipt = new StringBuilder();
        public StringBuilder Receipt
        {
            get { return receipt; }
            set { receipt = value; }
        }

        private Guid jobId = Guid.NewGuid();
        public Guid JobId
        {
            get { return jobId; }
            set { jobId = value; }
        }

        bool seatIsAppended = false;
        public bool SeatIsAppended
        {
            get { return seatIsAppended; }
            set { seatIsAppended = value; }
        }
    }


    public class PrintSpool
    {
        private static int _jobCounter = 0;

        private static bool useCurrentDay = false;
        public static bool UseCurrentDay
        {
            get { return useCurrentDay; }
            set { useCurrentDay = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<string> GetSharedPrinterNames()
        {
            List<string> printers = new List<string>();
            try
            {
                ///Get Remote Printers
                PrintRaw.LoginToShare(Constants.PrintServerPath, Constants.PrintServerUserName, Constants.PrintServerPassword);
                using (PrintServer printServer = new PrintServer(Constants.PrintServerPath))
                {
                    using (PrintQueueCollection printServerQueues = printServer.GetPrintQueues())
                    {
                        if (printServerQueues != null && printServerQueues.Count() != 0)
                        {
                            foreach (PrintQueue pq in printServerQueues)
                            {
                                if (pq.IsShared)
                                {
                                    printers.Add(pq.FullName);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return printers;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<string> GetAllPrinterNames(bool sharedFromDb = false)
        {
            ///Get Remote Printers            
            List<string> printers;

            if (sharedFromDb)
            {
                printers = new List<string>();
                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    var q = from P in context.PRINTERS
                            where P.IsDeleted == false
                            select P;

                    if (q.Any())
                    {
                        foreach (PRINTER pgp in q)
                        {
                            if (!String.IsNullOrEmpty(pgp.Name))
                            {
                                printers.Add(pgp.Name);
                            }
                        }
                    }
                }
            }
            else
            {
                printers = GetSharedPrinterNames();
            }

            ///Get local printers
            using (PrintServer printServer = new PrintServer())
            {
                using (PrintQueueCollection printServerQueues = printServer.GetPrintQueues())
                {
                    if (printServerQueues != null && printServerQueues.Count() != 0)
                    {
                        foreach (PrintQueue pq in printServerQueues)
                        {
                            printers.Add(pq.FullName);
                        }
                    }
                }
            }
            return printers;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static string PrintJobName()
        {
            try
            {
                return Constants.IpHostName.HostName.ToString() + "-" + (++_jobCounter).ToString();
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }

            ///Failsafe way just in case the host name causes an exception.
            return (++_jobCounter).ToString();
        }

        public static void OpenDrawerTwoAsync(Int64 localPrinterId)
        {
            string path = PRINTER.GetPrinterPathById(localPrinterId);
            if (path != null)
            {
                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    try
                    {
                        PrintRaw.SendStringToPrinter(path, PrintConst.DRAWER2 + PrintConst.CR, "OpenDrawerTwo");
                    }
                    catch (Exception ex)
                    {
                        Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_OPEN_CASH_DRAWER, ex);
                    }
                });
            }
        }

        public static void OpenDrawerOneAsync(Int64 localPrinterId)
        {
            string path = PRINTER.GetPrinterPathById(localPrinterId);
            if (path != null)
            {
                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    try
                    {
                        PrintRaw.SendStringToPrinter(path, PrintConst.DRAWER1 + PrintConst.CR, "OpenDrawerOne");
                    }
                    catch (Exception ex)
                    {
                        Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_OPEN_CASH_DRAWER, ex);
                    }
                });
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="printerPath"></param>
        /// <param name="sb"></param>
        private static void Print(string printerPath, StringBuilder sb)
        {
            bool didPrint = false;
            bool didLogin = false;

            try
            {
                try
                {
                    ///Make sure we have access to the share by providing credentials. This is for the remote print server only.
                    string pServer = Constants.PrintServerPath;
                    PrintRaw.LoginToShare(pServer, Constants.PrintServerUserName, Constants.PrintServerPassword);
                    didLogin = true;

                    using (PrintServer printServer = new PrintServer(pServer))
                    {
                        using (PrintQueueCollection printServerQueues = printServer.GetPrintQueues())
                        {
                            if (printServerQueues != null && printServerQueues.Count() != 0)
                            {
                                foreach (PrintQueue pq in printServerQueues)
                                {
                                    if (pq.FullName.Equals(printerPath))
                                    {
                                        string pJobName = PrintJobName();
                                        Int32 jobId = PrintRaw.SendStringToPrinter(printerPath, sb.ToString(), pJobName);
                                        QueuedPrintJob.QueueJob(jobId, pJobName, pq.ShareName, pServer, printerPath);
                                        didPrint = true;
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception) { }

                ///In this case it is a local printjob??
                if (!didPrint)
                {
                    ///Get local printers
                    using (PrintServer printServer = new PrintServer())
                    {
                        using (PrintQueueCollection printServerQueues = printServer.GetPrintQueues())
                        {
                            if (printServerQueues != null && printServerQueues.Count() != 0)
                            {
                                foreach (PrintQueue pq in printServerQueues)
                                {
                                    if (pq.FullName.Equals(printerPath))
                                    {
                                        string pJobName = PrintJobName();
                                        Int32 jobId = PrintRaw.SendStringToPrinter(printerPath, sb.ToString(), pJobName);
                                        QueuedPrintJob.QueueJob(jobId, pJobName, printerPath, null, printerPath);
                                        didPrint = true;
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            finally
            {
                if (!didLogin)
                {
                    Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_PRINT,
                        new Exception("Could not Login to Print Server"), new object[] { sb });
                }
                else if (!didPrint)
                {
                    Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_PRINT,
                        new Exception("Printer not Found"), new object[] { sb });
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByMenuGroup(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;
                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.ProductsMainCatId).
                                OrderByDescending(g => g.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)))))
                            {
                                decimal amount = salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                grandTotal += amount;

                                Int64 id;
                                string name = null;
                                id = salesGroups.First().ProductsMainCatId;

                                if (salesGroups.First().IsExceptionModifier)
                                {
                                    name = "$ " + logContext.EXCEPTION_MODIFIER_GROUPS.Where(pg => pg.Id == id).FirstOrDefault().Name;
                                }
                                else if (salesGroups.First().IsForcedModifier)
                                {
                                    name = "$ " + logContext.FORCED_MODIFIER_GROUPS.Where(pg => pg.Id == id).FirstOrDefault().Name;
                                }
                                else
                                {
                                    name = "$ " + logContext.PRODUCT_GROUPS.Where(pg => pg.Id == id).FirstOrDefault().Name;
                                }

                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (amount.ToString("c").Length + name.Length), ' ');
                                receipt.AppendLine(amount.ToString("c"));
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByRevenueType(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;

                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.RevenueTypeId).OrderByDescending(g => g.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)))))
                            {
                                decimal amount = salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                grandTotal += amount;
                                Int64 id = salesGroups.First().RevenueTypeId;
                                string name = "$ " + logContext.REVENUE_TYPES.Where(rt => rt.Id == id).FirstOrDefault().Name;
                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (amount.ToString("c").Length + name.Length), ' ');
                                receipt.AppendLine(amount.ToString("c"));
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByDaypart(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;

                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.DaypartId).OrderByDescending(g => g.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)))))
                            {
                                decimal amount = salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                grandTotal += amount;
                                Int64 id = salesGroups.First().DaypartId;
                                string name = "$ " + logContext.DAYPARTS.Where(dp => dp.Id == id).FirstOrDefault().Name;
                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (amount.ToString("c").Length + name.Length), ' ');
                                receipt.AppendLine(amount.ToString("c"));
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByRevenueCenter(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;

                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.RevenueCenterId).OrderByDescending(g => g.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)))))
                            {
                                decimal amount = salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                grandTotal += amount;
                                Int64 id = salesGroups.First().RevenueCenterId;
                                string name = "$ " + logContext.REVENUE_CENTERS.Where(rc => rc.Id == id).FirstOrDefault().Name;
                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (amount.ToString("c").Length + name.Length), ' ');
                                receipt.AppendLine(amount.ToString("c"));
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByCountOrdered(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;

                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.ProductId).OrderByDescending(g => g.Sum(s => s.CountOrdered)))
                            {
                                int count = salesGroups.Sum(s => s.CountOrdered);
                                grandTotal += salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                string name = "# " + salesGroups.First().ProductName;
                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (count.ToString().Length + name.Length), ' ');
                                receipt.AppendLine(count.ToString());
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public static void PrintSalesByEmployee(DateTime? start = null, DateTime? end = null)
        {
            try
            {
                using (DominicaEntities logContext = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    decimal grandTotal = 0M;

                    KIOSK k = KIOSK.Get(logContext);
                    if (k.LocalPrinterId != null)
                    {
                        string path = logContext.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;

                        List<SALE> salesList = new List<SALE>();
                        List<BUSINESS_DAY> bdays = new List<BUSINESS_DAY>();

                        if (start == null || end == null)
                        {
                            bdays.Add(BUSINESS_DAY.GetNow(logContext));
                        }
                        else
                        {
                            DateTime startNotNull = (DateTime)start;
                            DateTime endNotNull = (DateTime)end;

                            start = new DateTime(startNotNull.Year, startNotNull.Month, startNotNull.Day, 0, 0, 0);
                            end = new DateTime(endNotNull.Year, endNotNull.Month, endNotNull.Day, 23, 59, 59);

                            bdays = logContext.BUSINESS_DAYS.
                                Where(b => b.BusinessDayDateStamp >= start && b.BusinessDayDateStamp <= end).ToList();

                            if (UseCurrentDay)
                            {
                                UseCurrentDay = false;
                                BUSINESS_DAY nowBday = BUSINESS_DAY.GetNow(logContext);
                                if (nowBday != null && !bdays.Where(bd => bd.Id == nowBday.Id).Any())
                                {
                                    if (bdays == null)
                                    {
                                        bdays = new List<BUSINESS_DAY>();
                                    }
                                    bdays.Add(nowBday);
                                }
                            }
                        }
                        if (bdays != null)
                        {
                            foreach (BUSINESS_DAY bd in bdays)
                            {
                                List<ORDER> ordersList = logContext.ORDERS.Where(o => o.BusinessDayId == bd.Id).ToList();

                                foreach (ORDER order in ordersList)
                                {
                                    foreach (SALE sale in order.SALES.Where(s => !s.WasCompedInEntire
                                        && !s.WasVoided && s.ActualPrice != 0 && !s.IsSeeServer))
                                    {
                                        salesList.Add(sale);
                                    }
                                }
                            }
                        }
                        if (salesList.Count() > 0)
                        {
                            StringBuilder receipt = new StringBuilder();
                            Helpers.Init(receipt);
                            receipt.Append(PrintConst.PRINTLOGO);
                            Helpers.AppendHeader(receipt, null);

                            foreach (IGrouping<Int64, SALE> salesGroups in salesList.GroupBy(g => g.UserId).
                                OrderByDescending(g => g.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)))))
                            {
                                decimal amount = salesGroups.Sum(s => s.CountOrdered * (s.ActualPrice - (s.ActualPrice * s.DiscountRate)));
                                grandTotal += amount;
                                Int64 id = salesGroups.First().UserId;
                                USER user = logContext.USERS.Where(u => u.Id == id).FirstOrDefault();
                                string name = user.FirstName + " " + user.LastName;
                                receipt.Append(name);
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                    (amount.ToString("c").Length + name.Length), ' ');
                                receipt.AppendLine(amount.ToString("c"));
                            }

                            ///Add a dashed line
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Adjusted:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total Adjusted:".Length - grandTotal.ToString("c").Length, ' ');
                            receipt.Append(grandTotal.ToString("c") + PrintConst.NL);

                            ///Spacing                    
                            receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                            Print(path, receipt);
                        }
                        else
                        {
                            UMD.ShowGuiMessageSTASafe_NOTHROW("There is no data in the selected report.");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                UMD.ShowGuiMessageSTASafe_NOTHROW("An error was encountered and the system was unable to generate a report.");
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<PrintObject> GetPrinterGroupingsNeededForOrder(ORDER table)
        {
            List<PrintObject> printersList = new List<PrintObject>();
            KIOSK k = KIOSK.Get(SHIFT.GlobalContext);

            foreach (SALE sale in table.SALES)
            {
                if (sale.PrinterGroupingId != null && sale.PrinterGroupingId != 0
                    && sale.CountPendingKitchenSend != 0 && sale.OnHold == false)
                {
                    ///Now assure that this products main product group is not in the exclusion group for dispatched printing.
                    if (!sale.IsForcedModifier && !sale.IsExceptionModifier)
                    {
                        if (!k.PRODUCT_GROUP_PRINTER_EXCLUSIONS.Where(ex => ex.ProductGroupId == sale.ProductsMainCatId).Any())
                        {
                            Helpers.AddPrinterGrouping((long)sale.PrinterGroupingId, printersList);
                        }
                        else
                        {
                            sale.CountPendingKitchenSend = 0;
                        }
                    }
                    else
                    {
                        Int64 prodId = sale.PARENTSALE_WHEN_MODSALE.ProductsMainCatId;
                        if (prodId == 0)
                        {
                            ///ERROR Condition.
                            Logging.LogMessage(sale.ProductName + " had a main cat id of " + prodId + ".");
                            sale.CountPendingKitchenSend = 0;
                        }
                        else if (!k.PRODUCT_GROUP_PRINTER_EXCLUSIONS.Where(ex => ex.ProductGroupId == prodId).Any())
                        {
                            Helpers.AddPrinterGrouping((long)sale.PrinterGroupingId, printersList);
                        }
                        else
                        {
                            sale.CountPendingKitchenSend = 0;
                        }
                    }
                }
            }
            return printersList;
        }

        public static PrintObject GetPrinterObject(Int64 pid, List<PrintObject> list)
        {
            foreach (PrintObject po in list)
            {
                if (po.PrinterGroupingId == pid)
                {
                    return po;
                }
            }
            return null;
        }

        public static void PrintPosPayrollReportAsync(string printName, List<PAYROLL_RUN.PayType> listOfReports,
                        DateTime startDate, DateTime endDate)
        {
            try
            {
                System.Threading.Tasks.Task.Factory.StartNew(() => PrintPosPayrollReportSync(printName, listOfReports, startDate, endDate));
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }
        public static void PrintPosPayrollReportSync(string printName,
            List<PAYROLL_RUN.PayType> listOfPayTypes,
            DateTime startDate, DateTime endDate)
        {
            decimal total = 0M;
            try
            {
                StringBuilder receipt = new StringBuilder();

                if (listOfPayTypes != null && listOfPayTypes.Count != 0)
                {
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    receipt.Append(PrintConst.NL + PrintConst.NL);
                    receipt.Append(PrintConst.BOLD + "Payroll Report for Period: " + PrintConst.NL + PrintConst.NL);
                    receipt.Append(startDate.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                    receipt.Append(startDate.ToString(" h:mm tt", CultureInfo.CreateSpecificCulture("en-US")));

                    receipt.Append(" to " + endDate.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                    receipt.Append(endDate.ToString(" h:mm tt", CultureInfo.CreateSpecificCulture("en-US"))
                        + PrintConst.NL + PrintConst.NORMAL);

                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    var q = listOfPayTypes.Select(x => x.UserId).Distinct();
                    if (q.Any())
                    {
                        List<Int64> listOfInts = q.ToList();
                        foreach (Int64 userId in listOfInts)
                        {
                            var pr = from pt in listOfPayTypes where pt.UserId == userId select pt;
                            if (pr.Any())
                            {
                                List<PAYROLL_RUN.PayType> payTypesList = pr.ToList();
                                decimal employeeGross = 0M;
                                bool isFirst = true;
                                foreach (PAYROLL_RUN.PayType pt in payTypesList)
                                {
                                    if (isFirst)
                                    {
                                        isFirst = false;

                                        receipt.Append(PrintConst.NL + PrintConst.BOLD + "Employee: #" + pt.UserId + " "
                                            + pt.FullName + PrintConst.NL + PrintConst.NORMAL);
                                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                                        receipt.Append(PrintConst.PAYROLLHEADERSTR + PrintConst.NL);
                                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                                    }

                                    string jcodeName = pt.RoleId + " " + pt.JobCode.Name;
                                    if (jcodeName != null && jcodeName.Length > PrintConst.JOBCODESTRSIZE - 1)
                                    {
                                        jcodeName = jcodeName.Substring(0, PrintConst.JOBCODESTRSIZE - 1);
                                    }
                                    receipt.Append(jcodeName);
                                    Helpers.PaddWithChar(receipt, (PrintConst.JOBCODESTRSIZE - jcodeName.Length), ' ');

                                    string hours = pt.TotalHours.ToString("0.00");
                                    Helpers.PaddWithChar(receipt, (PrintConst.HOURSSTRSIZE - hours.Length), ' ');
                                    receipt.Append(hours);

                                    string grossForJobcode = pt.GrossPay.ToString("c");
                                    employeeGross += pt.GrossPay;
                                    Helpers.PaddWithChar(receipt, (PrintConst.GROSSSTRSIZE - grossForJobcode.Length), ' ');
                                    receipt.Append(grossForJobcode + PrintConst.NL);
                                }
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Employee Gross Pay: ".Length - employeeGross.ToString("c").Length, ' ');
                                receipt.Append("Employee Gross Pay: " + employeeGross.ToString("c") + PrintConst.NL);
                                total += employeeGross;
                            }
                        }
                    }

                    ///Add a dashed line
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Gross Payout: ".Length - total.ToString("c").Length, ' ');
                    receipt.Append("Gross Payout: ");
                    receipt.Append(total.ToString("c") + PrintConst.NL);

                    ///Spacing                    
                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    Print(printName, receipt);
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_PRINT, ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="printName"></param>
        /// <param name="listOfReports"></param>
        public static void PrintCompReportReceiptAsync(string printName,
            List<SALE.CompReport> listOfReports, DateTime startDate, DateTime endDate)
        {
            try
            {
                System.Threading.Tasks.Task.Factory.StartNew(() => PrintCompReportReceiptSync(printName, listOfReports, startDate, endDate));
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }
        public static void PrintCompReportReceiptSync(string printName, List<SALE.CompReport> listOfReports,
            DateTime startDate, DateTime endDate)
        {
            decimal total = 0M;
            try
            {
                StringBuilder receipt = new StringBuilder();

                if (listOfReports != null && listOfReports.Count != 0)
                {
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    receipt.Append(PrintConst.NL + PrintConst.NL);
                    receipt.Append(PrintConst.BOLD + "Comp Report for Period: " + PrintConst.NL + PrintConst.NL);
                    receipt.Append(startDate.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                    receipt.Append(startDate.ToString(" h:mm tt", CultureInfo.CreateSpecificCulture("en-US")));

                    receipt.Append(" to " + endDate.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                    receipt.Append(endDate.ToString(" h:mm tt", CultureInfo.CreateSpecificCulture("en-US"))
                        + PrintConst.NL + PrintConst.NORMAL);

                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    foreach (SALE.CompReport report in listOfReports)
                    {
                        int paddCount = 0;
                        string countStr = report.CountStr;
                        string nameStr;

                        int lastIndex = report.Comp.Name.Length - 1;
                        if (lastIndex > 14)
                        {
                            lastIndex = 14;
                            nameStr = " " + report.Comp.Name.Substring(0, lastIndex);
                        }
                        else
                        {
                            nameStr = " " + report.Comp.Name;
                        }

                        string salesStr = report.Sales.ToString("c");
                        total += report.Sales;

                        receipt.Append(countStr);
                        paddCount = Helpers.PaddWithChar(receipt, (Constants.CONST_MAX_REPORT_LINE_NUM_WIDTH - countStr.Length), ' ');
                        receipt.Append(nameStr);

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - countStr.Length - nameStr.Length - salesStr.Length - paddCount, ' ');
                        receipt.Append(salesStr + PrintConst.NL);
                    }

                    ///Add a dashed line
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - "Total: ".Length - total.ToString("c").Length, ' ');
                    receipt.Append("Total: ");
                    receipt.Append(total.ToString("c") + PrintConst.NL);

                    ///Spacing                    
                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    Print(printName, receipt);
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_PRINT, ex);
            }
        }

        public static void PrintTotalReceipt(Int64 printerId, decimal total, ORDER table)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(printerId);
                if (path != null)
                {
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    Helpers.AppendHeader(receipt, table);

                    receipt.Append("Total: ");
                    receipt.Append(total.ToString("c") + PrintConst.NL);
                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);

                    Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }

        public static void PrintSeatsSubTotalReceipt(Int64 printerId, int seatNo, ORDER table)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(printerId);
                if (path != null)
                {
                    decimal total = table.SpecifiedSeatBarSubtotal(POBindings.SelectedSeatIndex);

                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    Helpers.AppendHeader(receipt, table, null, true, (seatNo + 1).ToString());
                    receipt.Append("Subtotal: ");
                    receipt.Append(total.ToString("c") + PrintConst.NL);
                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);

                    Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }


        public static void PrintCheckout(string path, 
            SHIFT.SHIFT_CHECKOUTDATA shiftData, 
            StringBuilder batchData = null, 
            bool stopStoryBoard = false)
        {
            try
            {
                if ((shiftData != null) && ((shiftData.isHouseCloseout && shiftData.businessDay != null)
                    || (!shiftData.isHouseCloseout && shiftData.shift != null && shiftData.shift.DateStamp != null)))
                {
                    bool empty = true;
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    receipt.AppendLine("\n");

                    SYSCONFIG syscfg = SYSCONFIG.Get(SHIFT.GlobalContext);
                    receipt.Append(PrintConst.CENTER);

                    if (!string.IsNullOrEmpty(syscfg.ReceiptLine1))
                    {
                        receipt.AppendLine();
                        receipt.AppendLine(syscfg.ReceiptLine1);
                    }
                    if (!string.IsNullOrEmpty(syscfg.ReceiptLine2))
                    {
                        receipt.AppendLine(syscfg.ReceiptLine2);
                    }
                    if (!string.IsNullOrEmpty(syscfg.ReceiptLine3))
                    {
                        receipt.AppendLine(syscfg.ReceiptLine3);
                    }
                    if (!string.IsNullOrEmpty(syscfg.ReceiptLine4))
                    {
                        receipt.AppendLine(syscfg.ReceiptLine4);
                    }

                    receipt.AppendLine("\n");
                    receipt.Append(PrintConst.BLACK + PrintConst.LEFT + PrintConst.BOLD);
                    if (shiftData.isHouseCloseout)
                    {
                        receipt.Append("     *****   House Checkout  ***** " + PrintConst.NL + PrintConst.NL);
                    }
                    else
                    {
                        receipt.Append("     ***** Employee Checkout ***** " + PrintConst.NL + PrintConst.NL);
                    }
                    DateTime rightNow = DateTime.Now;
                    receipt.Append("PRINTED ON: ");
                    receipt.Append(rightNow.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                    receipt.Append(" Time: " + rightNow.ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US")) + PrintConst.NL);

                    if (shiftData.isHouseCloseout)
                    {
                        if (shiftData.businessDay != null && shiftData.businessDay.BusinessDayDateStamp != null)
                        {
                            receipt.Append("BUSINESS DATE: ");
                            receipt.Append(shiftData.businessDay.BusinessDayDateStamp.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")) + PrintConst.NL);
                        }
                    }
                    else
                    {
                        if (shiftData.shift != null && shiftData.shift.DateStamp != null)
                        {
                            receipt.Append("SHIFT DATE: ");
                            receipt.Append(shiftData.shift.DateStamp.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")) + PrintConst.NL);
                        }
                    }
                    ///Add a dashed line
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    if (!shiftData.isHouseCloseout)
                    {
                        if (shiftData.user != null)
                        {
                            receipt.Append("EMPLOYEE NAME : " + shiftData.user.FirstName + " " + shiftData.user.LastName + PrintConst.NL + PrintConst.NL);
                        }

                        if (shiftData.clockedInDp != null)
                        {
                            receipt.Append("IN DAYPART    : " + shiftData.clockedInDp.Name + PrintConst.NL);
                        }
                        if (shiftData.clockedOutDp != null)
                        {
                            receipt.Append("OUT DAYPART   : " + shiftData.clockedOutDp.Name + PrintConst.NL + PrintConst.NL);
                        }

                        if (shiftData.revCenter != null)
                        {
                            receipt.Append("REVENUE CENTER: " + shiftData.revCenter.Name + PrintConst.NL + PrintConst.NL);
                        }
                        if (shiftData.role != null && shiftData.role.JOB_CODE != null)
                        {
                            receipt.Append("JOB CODE      : " + shiftData.role.JOB_CODE.Name + PrintConst.NL);
                            receipt.Append("ROLE NAME     : " + shiftData.role.Name + PrintConst.NL + PrintConst.NL);
                        }
                        if (shiftData.shift.TIMESLIP != null && shiftData.shift.TIMESLIP.ClockedIn != null)
                        {
                            receipt.Append("CLOCKED IN : ");
                            receipt.Append(shiftData.shift.TIMESLIP.ClockedIn.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                            receipt.Append(" Time: " + shiftData.shift.TIMESLIP.ClockedIn.ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US")) + PrintConst.NL);
                        }

                        if (shiftData.shift.TIMESLIP != null && shiftData.shift.TIMESLIP.ClockedOut != null)
                        {
                            receipt.Append("CLOCKED OUT: ");
                            receipt.Append(((DateTime)shiftData.shift.TIMESLIP.ClockedOut).ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US")));
                            receipt.Append(" Time: " + ((DateTime)shiftData.shift.TIMESLIP.ClockedOut).ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US")) + PrintConst.NL + PrintConst.NL);
                            receipt.Append("BREAK COUNT: " + shiftData.shift.TIMESLIP.BREAKS.Count() + PrintConst.NL);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        }
                    }
                    receipt.AppendLine();
                    receipt.Append("     *********** Sales *********** " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.salesGroupByRevType.Count != 0)
                    {
                        foreach (IGrouping<Int64, SHIFT.SALES_BY_REVTYPE> grouping in shiftData.salesGroupByRevType.GroupBy(s => s.rtId))
                        {
                            decimal sum = grouping.Sum(s => s.total);
                            if (sum != 0)
                            {
                                string name = grouping.First().rtName;
                                receipt.Append(name);
                                string totalString = (sum).ToString("c");
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (name.Length + totalString.Length), ' ');
                                receipt.AppendLine(totalString);
                            }
                        }
                        if (shiftData.totalSales != 0)
                        {
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Sales:");
                            string grandTotalStr = shiftData.totalSales.ToString("c");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total Sales:".Length + grandTotalStr.Length), ' ');
                            receipt.AppendLine(grandTotalStr);

                            receipt.Append("Plate Count:");
                            string plateCountStr = shiftData.plateCount.ToString();
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Plate Count:".Length + plateCountStr.Length), ' ');
                            receipt.AppendLine(plateCountStr);

                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Plate Average:");
                            string plateAverageStr = (shiftData.totalSales / shiftData.plateCount).ToString("c");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Plate Average:".Length + plateAverageStr.Length), ' ');
                            receipt.AppendLine(plateAverageStr);
                        }
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }


                    receipt.AppendLine();

                    receipt.Append("     *********** Comps *********** " + PrintConst.NL + PrintConst.NL);
                    empty = true;
                    foreach (IGrouping<Int64, SHIFT.COMPS_BY_COMPTYPE> a in shiftData.salesGroupByCompType.GroupBy(s => s.ctId))
                    {
                        string rtname = a.First().ctName.ToUpper() + ":";
                        empty = false;
                        receipt.Append(rtname);
                        string totalString = a.Sum(s => s.total).ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (rtname.Length + totalString.Length), ' ');
                        receipt.AppendLine(totalString);
                    }
                    if (empty)
                    {
                        receipt.AppendLine("None");
                    }
                    else
                    {
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total:");
                        string grandTotalStr = shiftData.totalComps.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }

                    receipt.AppendLine();
                    receipt.Append("     *********** Voids *********** " + PrintConst.NL + PrintConst.NL);
                    empty = true;
                    foreach (IGrouping<Int64, SHIFT.VOIDS_BY_VOIDTYPE> a in shiftData.salesGroupByVoidType.GroupBy(s => s.vtId))
                    {
                        string rtname = a.First().vtName.ToUpper() + ":";
                        empty = false;
                        receipt.Append(rtname);
                        string totalString = a.Sum(s => s.total).ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (rtname.Length + totalString.Length), ' ');
                        receipt.AppendLine(totalString);
                    }
                    if (empty)
                    {
                        receipt.AppendLine("None");
                    }
                    else
                    {
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total:");
                        string grandTotalStr = shiftData.totalVoids.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }

                    receipt.AppendLine();
                    empty = true;
                    receipt.Append("     *********** Promos ********** " + PrintConst.NL + PrintConst.NL);
                    empty = true;
                    foreach (IGrouping<Int64, SHIFT.PROMOS_BY_PROMOTYPE> a in shiftData.salesGroupByPromoType.GroupBy(s => s.ptId))
                    {
                        string rtname = a.First().ptName.ToUpper() + ":";
                        empty = false;
                        receipt.Append(rtname);
                        string totalString = a.Sum(s => s.total).ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (rtname.Length + totalString.Length), ' ');
                        receipt.AppendLine(totalString);
                    }
                    if (empty)
                    {
                        receipt.AppendLine("None");
                    }
                    else
                    {
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total:");
                        string grandTotalStr = shiftData.totalPromo.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }

                    receipt.AppendLine();
                    receipt.Append("     ****** Gift Cards Sold ****** " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.giftCardAmountSold != 0)
                    {
                        receipt.Append("Total:");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + shiftData.giftCardAmountSold.ToString("c").Length), ' ');
                        receipt.AppendLine(shiftData.giftCardAmountSold.ToString("c"));
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }


                    receipt.AppendLine();
                    receipt.Append("     ****** Exclusive Taxes ****** " + PrintConst.NL + PrintConst.NL);

                    if (shiftData.totalExclusiveTaxes != 0)
                    {
                        receipt.Append("Exclusively Taxable Sales:");
                        string taxableSalesString = shiftData.exclusivelyTaxableSales.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Exclusively Taxable Sales:".Length
                            + taxableSalesString.Length), ' ');
                        receipt.AppendLine(taxableSalesString);

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total Collected:");
                        string grandTotalStr = shiftData.totalExclusiveTaxes.ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total Collected:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    receipt.Append("     ****** Inclusive Taxes ****** " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.inclusivelyTaxableSales != 0)
                    {
                        receipt.Append("Inclusively Taxable Sales:");
                        string taxableSalesString = shiftData.inclusivelyTaxableSales.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Inclusively Taxable Sales:".Length
                            + taxableSalesString.Length), ' ');
                        receipt.AppendLine(taxableSalesString);
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                        foreach (IGrouping<Int64, SHIFT.INCLUSIVE_TAX_BY_TAXTYPE> grouping in shiftData.salesGroupByInclusiveType.GroupBy(s => s.tId))
                        {
                            receipt.AppendLine(grouping.First().name + Constants.NEWLINE);
                            string inctaxStr = grouping.Sum(s => s.incTax).ToString("c");
                            string grossSalesStr = grouping.Sum(s => s.grossSales).ToString("c");
                            string netSalesStr = grouping.Sum(s => s.netSales).ToString("c");

                            receipt.Append("Gross Sales:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Gross Sales:".Length + grossSalesStr.Length), ' ');
                            receipt.AppendLine(grossSalesStr);

                            receipt.Append("Net Sales:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Net Sales:".Length + netSalesStr.Length), ' ');
                            receipt.AppendLine(netSalesStr);

                            receipt.Append("Inclusive Tax:");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Inclusive Tax:".Length + inctaxStr.Length), ' ');
                            receipt.AppendLine(inctaxStr);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        }

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total Inclusive:");
                        string grandTotalStr = shiftData.totalInclusiveTaxes.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total Inclusive:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }


                    receipt.AppendLine();
                    receipt.Append("     *** House Payment Summary *** " + PrintConst.NL + PrintConst.NL);


                    if (shiftData.houseAccountByType.Count != 0)
                    {
                        foreach (SHIFT.HOUSE_ACCOUNT_BY_TYPE hap in shiftData.houseAccountByType)
                        {
                            string name = hap.name;
                            decimal total = hap.total;
                            receipt.Append(name);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (name.Length + total.ToString("c").Length), ' ');
                            receipt.AppendLine(total.ToString("c"));
                        }

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total:");
                        string grandTotalStr = shiftData.houseTransactionsTotal.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    receipt.Append("     ********** Payments ********* " + PrintConst.NL + PrintConst.NL);


                    if (shiftData.transactionsByTypeList.Count != 0)
                    {
                        foreach (IGrouping<Int64, SHIFT.TRANSACTIONS_BY_TRANSACTION_TYPE> grouping in shiftData.transactionsByTypeList.GroupBy(s => s.tTypeId))
                        {
                            string name = grouping.First().name;
                            decimal total = grouping.Sum(s => s.total);
                            receipt.Append(name);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (name.Length + total.ToString("c").Length), ' ');
                            receipt.AppendLine(total.ToString("c"));
                        }

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Total:");
                        string grandTotalStr = shiftData.paymentTotal.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total:".Length + grandTotalStr.Length), ' ');
                        receipt.AppendLine(grandTotalStr);
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    receipt.Append("     ****** Credit Card Tips ***** " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.creditCardTipTotal != 0)
                    {
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append("Credit Card Tips:");
                        string tipTotalStr = shiftData.creditCardTipTotal.ToString("c");

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Credit Card Tips:".Length + tipTotalStr.Length), ' ');
                        receipt.AppendLine(tipTotalStr);
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    receipt.Append("     ********** Paid In ********** " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.paidInByType.Count != 0)
                    {
                        foreach (IGrouping<Int64, SHIFT.PAIDIN_BY_TYPE> grouping in shiftData.paidInByType.GroupBy(s => s.reasonId))
                        {
                            decimal sum = grouping.Sum(s => s.total);
                            if (sum != 0)
                            {
                                string name = grouping.First().name;
                                receipt.Append(name);
                                string totalString = (sum).ToString("c");
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (name.Length + totalString.Length), ' ');
                                receipt.AppendLine(totalString);
                            }
                        }
                        if (shiftData.totalPaidIn != 0)
                        {
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Paid In:");
                            string grandTotalStr = shiftData.totalPaidIn.ToString("c");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total Paid In:".Length + grandTotalStr.Length), ' ');
                            receipt.AppendLine(grandTotalStr);
                        }
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    receipt.Append("     ********** Paid Out ********* " + PrintConst.NL + PrintConst.NL);
                    if (shiftData.paidOutByType.Count != 0)
                    {
                        foreach (IGrouping<Int64, SHIFT.PAIDOUT_BY_TYPE> grouping in shiftData.paidOutByType.GroupBy(s => s.reasonId))
                        {
                            decimal sum = grouping.Sum(s => s.total);
                            if (sum != 0)
                            {
                                string name = grouping.First().name;
                                receipt.Append(name);
                                string totalString = (sum).ToString("c");
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (name.Length + totalString.Length), ' ');
                                receipt.AppendLine(totalString);
                            }
                        }
                        if (shiftData.totalPaidOut != 0)
                        {
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.Append("Total Paid Out:");
                            string grandTotalStr = shiftData.totalPaidOut.ToString("c");
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("Total Paid Out:".Length + grandTotalStr.Length), ' ');
                            receipt.AppendLine(grandTotalStr);
                        }
                    }
                    else
                    {
                        receipt.AppendLine("None");
                    }

                    receipt.AppendLine();
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    receipt.Append("     ****** Checkout Summary ***** " + PrintConst.NL + PrintConst.NL);
                    receipt.Append(" +Total Sales:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (" +Total Sales:".Length + shiftData.totalSales.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.totalSales.ToString("c"));

                    receipt.Append(" +Exclusive Tax:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (" +Exclusive Tax:".Length + shiftData.totalExclusiveTaxes.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.totalExclusiveTaxes.ToString("c"));

                    if (!shiftData.isHouseCloseout)
                    {
                        receipt.Append(" +Drawer Start:");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (" +Drawer Start:".Length + shiftData.shift.DrawerStart.ToString("c").Length), ' ');
                        receipt.AppendLine(shiftData.shift.DrawerStart.ToString("c"));
                    }
                    else
                    {
                        receipt.Append(" +Today's Cash Start:");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (" +Today's Cash Start:".Length + shiftData.dayCashStart.ToString("c").Length), ' ');
                        receipt.AppendLine(shiftData.dayCashStart.ToString("c"));
                    }

                    receipt.Append(" +Paid In:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (" +Paid In:".Length + shiftData.totalPaidIn.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.totalPaidIn.ToString("c"));

                    receipt.Append("  -Total Discounts:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Total Discounts:".Length + shiftData.TotalDiscounts.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.TotalDiscounts.ToString("c"));

                    receipt.Append("  -Credit Transactions:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Credit Transactions:".Length + shiftData.creditTransactionTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.creditTransactionTotal.ToString("c"));

                    receipt.Append("  -Gift Transactions:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Gift Transactions:".Length + shiftData.giftCardTransTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.giftCardTransTotal.ToString("c"));

                    receipt.Append("  -Credit Card Tips:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Credit Card Tips:".Length + shiftData.creditCardTipTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.creditCardTipTotal.ToString("c"));

                    receipt.Append("  -Gift Card Tips:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Gift Card Tips:".Length + shiftData.giftCardTipTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.giftCardTipTotal.ToString("c"));

                    receipt.Append("  -House Transactions:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -House Transactions:".Length + shiftData.houseTransactionsTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.houseTransactionsTotal.ToString("c"));

                    receipt.Append("  -Paid Out:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Paid Out:".Length + shiftData.totalPaidOut.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.totalPaidOut.ToString("c"));

                    receipt.Append("  -Auto Gratuity:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("  -Auto Gratuity:".Length + shiftData.autoGratuityTotal.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.autoGratuityTotal.ToString("c"));

                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    receipt.Append("=Cash Due:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("=Cash Due:".Length + shiftData.TotalCash.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.TotalCash.ToString("c"));
                    receipt.Append("=Checks Due:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("=Checks Due:".Length + shiftData.TotalChecks.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.TotalChecks.ToString("c"));
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    receipt.Append("=Total Due:");
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("=Total Due:".Length + shiftData.TotalDue.ToString("c").Length), ' ');
                    receipt.AppendLine(shiftData.TotalDue.ToString("c"));
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    receipt.AppendLine();
                    if (!shiftData.isHouseCloseout && !Constants.IsQuickServiceMode)
                    {
                        receipt.Append("     *** Credit Transaction IDs ** " + PrintConst.NL + PrintConst.NL);
                        if (shiftData.ccTransactionIds != null && shiftData.ccTransactionIds.Count != 0)
                        {
                            foreach (Int64 id in shiftData.ccTransactionIds)
                            {
                                receipt.AppendLine("TRID: " + id);
                            }
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.AppendLine("Count = " + shiftData.ccTransactionIds.Count);
                        }
                        else
                        {
                            receipt.AppendLine("None");
                        }
                        receipt.AppendLine();
                        receipt.Append("     ***  Gift Transaction IDs *** " + PrintConst.NL + PrintConst.NL);
                        if (shiftData.gcTransactionIds != null && shiftData.gcTransactionIds.Count != 0)
                        {
                            foreach (Int64 id in shiftData.gcTransactionIds)
                            {
                                receipt.AppendLine("TRID: " + id);
                            }
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            receipt.AppendLine("Count = " + shiftData.gcTransactionIds.Count);
                        }
                        else
                        {
                            receipt.AppendLine("None");
                        }

                        receipt.AppendLine();
                        receipt.Append("     *** Receipts by Other User ** " + PrintConst.NL + PrintConst.NL);
                        if (shiftData.transactionsByAnotherUser.Count != 0)
                        {
                            receipt.AppendLine("The following transactions were");
                            receipt.AppendLine("applied to your orders but");
                            receipt.AppendLine("were initiated by another user.");
                            receipt.AppendLine("This should be considered when");
                            receipt.AppendLine("balancing your shift closeout with");
                            receipt.AppendLine("your manager." + Constants.NEWLINE);

                            receipt.AppendLine("Points to Consider:" + Constants.NEWLINE);
                            receipt.AppendLine("1) Any cash transactions accepted");
                            receipt.AppendLine("   by the other user should be ");
                            receipt.AppendLine("   given to you.");
                            receipt.AppendLine("2) If the user accepted a credit");
                            receipt.AppendLine("   card tip, your checkout will ");
                            receipt.AppendLine("   show this tip being owed to you." + Constants.NEWLINE);

                            using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                            {
                                foreach (TRANSACTION t in shiftData.transactionsByAnotherUser)
                                {
                                    receipt.AppendLine("TRID    : " + t.Id);
                                    receipt.AppendLine("USER    : " + context.USERS.Where(u => u.Id == t.UserId).FirstOrDefault().UserName);
                                    receipt.AppendLine("AMOUNT  : " + t.Base.ToString("c"));
                                    receipt.AppendLine("GRATUITY: " + t.Gratuity.ToString("c") + Constants.NEWLINE);
                                }
                            }
                        }
                    }
                    else if (shiftData.isHouseCloseout)
                    {
                        if (batchData != null)
                        {
                            receipt.AppendLine(batchData.ToString());
                        }
                    }


                    if (shiftData.isHouseCloseout)
                    {
                        using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                        {
                            BUSINESS_DAY bd = context.BUSINESS_DAYS.Where(b => b.Id == shiftData.businessDay.Id).FirstOrDefault();
                            var deposits = bd.DEPOSIT.Where(d => d.Amount < 0 && d.Type == null);
                            if (deposits.Any())
                            {
                                decimal total = 0M;
                                receipt.Append("     ********* Cash Drops ********" + PrintConst.NL + PrintConst.NL);
                                foreach (DEPOSIT d in deposits)
                                {
                                    USER user = context.USERS.Where(u => u.Id == d.EmployeeId).FirstOrDefault();
                                    string employee = user.FirstName + " " + user.LastName;
                                    receipt.Append("EMPLOYEE:");
                                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("EMPLOYEE:".Length + employee.Length), ' ');
                                    receipt.AppendLine(employee);
                                    receipt.Append("AMOUNT  :");
                                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("AMOUNT  :".Length + (-d.Amount).ToString("c").Length), ' ');
                                    receipt.AppendLine((-d.Amount).ToString("c") + Constants.NEWLINE);
                                    total += (-d.Amount);
                                }

                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                                receipt.Append("=Total:");
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ("=Total:".Length + total.ToString("c").Length), ' ');
                                receipt.AppendLine(total.ToString("c"));
                                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                            }

                        }
                    }

                    ///Spacing
                    receipt.Append(PrintConst.FEED5);

                    ///Employee signature line
                    Helpers.AddEmpSignatureLine(receipt, PrintConst.MAX_LINE_WIDTH);

                    ///Spacing
                    receipt.Append(PrintConst.FEED5);

                    ///Manager signature
                    Helpers.AddManagerSignatureLine(receipt, PrintConst.MAX_LINE_WIDTH);

                    ///Spacing
                    receipt.Append(PrintConst.FEED5);

                    ///Add a dashed line
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    ///Spacing
                    receipt.Append(PrintConst.FEED5);

                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);

                    ///Print this puppy.
                    Print(path, receipt);
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_PRINT, ex);
            }
            finally
            {
                if (stopStoryBoard)
                {
                    App.InvokeStopStoryBoard_NOTHROW();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwInterface"></param>
        /// <param name="table"></param>
        /// <param name="check"></param>
        /// <returns></returns>
        public static void PrintTotalReceiptAsync(Int64 localPrinterId,
            ORDER table,
            decimal baseAmount,
            Int64 oceansideID)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(localPrinterId);

                if (path != null)
                {
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    Helpers.AppendHeader(receipt, table);

                    receipt.Append(PrintConst.TOTALSTR);
                    string totalString = baseAmount.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.TOTALSTR.Length + totalString.Length)), ' ');
                    receipt.Append(totalString + PrintConst.NL);

                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    System.Threading.Tasks.Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }

        public static void PrintCashDropReceipt(Int64 localPrinterId, decimal amount, USER user, DateTime date)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(localPrinterId);

                if (path != null)
                {
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    Helpers.AppendHeader(receipt, null);

                    string dropTime = date.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US"));
                    dropTime += " " + date.ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US"));
                    receipt.Append("     *******   Cash Drop  *******" + PrintConst.NL);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    receipt.AppendLine("Employee: " + user.FirstName + " " + user.LastName + Constants.NEWLINE);
                    receipt.Append(PrintConst.TOTALSTR);
                    string totalString = amount.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.TOTALSTR.Length + totalString.Length)), ' ');
                    receipt.Append(totalString + PrintConst.NL);

                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    System.Threading.Tasks.Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }

        public static void PrintCashReceipt(Int64 localPrinterId,
                    ORDER table,
                    decimal due,
                    decimal tendered,
                    Int64 oceansideID,
                    int checkNo,
                    bool isCheckReceipt = false)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(localPrinterId);

                if (path != null)
                {
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);
                    Helpers.AppendPayHeader(receipt, table, (checkNo + 1).ToString());

                    if (oceansideID != 0)
                    {
                        receipt.Append(PrintConst.BOLD);
                        receipt.Append(PrintConst.OCEANSIDE_TRANSIDSTR);
                        string transactionIdStr = oceansideID.ToString();
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                            (PrintConst.OCEANSIDE_TRANSIDSTR.Length + transactionIdStr.Length), ' ');
                        receipt.Append(transactionIdStr + PrintConst.NL + PrintConst.NL);
                    }

                    receipt.Append(PrintConst.TOTALSTR);
                    string subtotalString = due.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.TOTALSTR.Length + subtotalString.Length)), ' ');
                    receipt.Append(subtotalString + PrintConst.NL);

                    if (isCheckReceipt)
                    {
                        receipt.Append(PrintConst.CHECKTNDRSTR);
                        string totalString = tendered.ToString("c");
                        Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.CHECKTNDRSTR.Length + totalString.Length)), ' ');
                        receipt.Append(totalString + PrintConst.NL);
                    }
                    else
                    {

                        receipt.Append(PrintConst.CASHTNDRSTR);
                        string totalString = tendered.ToString("c");
                        Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.CASHTNDRSTR.Length + totalString.Length)), ' ');
                        receipt.Append(totalString + PrintConst.NL);
                    }

                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    receipt.Append(PrintConst.CHANGESTR);
                    string changeString = (tendered - due).ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.CHANGESTR.Length + changeString.Length)), ' ');
                    receipt.Append(changeString + PrintConst.NL);
                    Helpers.AddCustomerFooter(receipt);
                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    System.Threading.Tasks.Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwInterface"></param>
        /// <param name="table"></param>
        /// <param name="check"></param>
        /// <param name="cardName"></param>
        /// <param name="cardNumber"></param>
        /// <returns></returns>
        public static void PrintCreditCardBatchReport(
            string printName,
            List<CREDIT_TRANSACTION_PRINT_PACKET> payments,
            DateTime houseDate
            )
        {
            try
            {
                StringBuilder receipt = new StringBuilder();
                Helpers.Init(receipt);
                receipt.Append(PrintConst.PRINTLOGO);

                receipt.Append(PrintConst.BLACK + PrintConst.LEFT + PrintConst.BOLD);
                receipt.Append("\nCARD BATCH REPORT FOR HOUSE CLOSE ON" + PrintConst.NL);
                string houseTime = houseDate.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US"));
                houseTime += " " + houseDate.ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US"));
                receipt.Append(houseTime + PrintConst.NL);
                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                receipt.Append(PrintConst.NORMAL);

                decimal grandSub = 0M;
                decimal grandTip = 0M;
                int count = 0;
                foreach (CREDIT_TRANSACTION_PRINT_PACKET payment in payments)
                {
                    count++;

                    decimal sub = payment.Transaction.Base;
                    grandSub += payment.Transaction.Base;

                    decimal tip = payment.Transaction.Gratuity;
                    grandTip += payment.Transaction.Gratuity;

                    if (payment.Transaction.OpenDateStamp != null)
                    {
                        receipt.Append(PrintConst.PAYTIME);
                        string payTime = payment.Transaction.OpenDateStamp.ToString("MM/dd/yy", CultureInfo.CreateSpecificCulture("en-US"));
                        payTime += " " + payment.Transaction.OpenDateStamp.ToString("h:mm tt", CultureInfo.CreateSpecificCulture("en-US"));

                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.PAYTIME.Length + payTime.Length), ' ');
                        receipt.Append(payTime + PrintConst.NL);
                    }

                    if (payment.TransactionResponse.TranCode != null)
                    {
                        receipt.Append(PrintConst.TRANSTYPE);
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                            (PrintConst.TRANSTYPE.Length + payment.TransactionResponse.TranCode.Length), ' ');
                        receipt.Append(payment.TransactionResponse.TranCode + PrintConst.NL);
                    }

                    if (payment.Transaction.CustomerName != null)
                    {
                        string trimName = payment.Transaction.CustomerName.Trim();
                        receipt.Append(PrintConst.CUSTNAME);
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.CUSTNAME.Length + trimName.Length), ' ');
                        receipt.Append(trimName + PrintConst.NL);
                    }

                    if (payment.TransactionResponse.CardType != null)
                    {
                        receipt.Append(PrintConst.TYPESTR);
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.TYPESTR.Length + payment.TransactionResponse.CardType.Length), ' ');
                        receipt.Append(payment.TransactionResponse.CardType + PrintConst.NL);
                    }

                    if (payment.TransactionResponse.Card4 != null)
                    {
                        receipt.Append(PrintConst.CARDNUMSTR);
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                            (payment.TransactionResponse.Card4.Length + PrintConst.CARDXSTR.Length + PrintConst.CARDNUMSTR.Length), ' ');
                        receipt.Append(PrintConst.CARDXSTR + payment.TransactionResponse.Card4 + PrintConst.NL);
                    }

                    receipt.Append(PrintConst.OCEANSIDE_TRANSIDSTR);
                    string orderNumberString = payment.Transaction.Id.ToString();
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                        (PrintConst.OCEANSIDE_TRANSIDSTR.Length + orderNumberString.Length), ' ');
                    receipt.Append(orderNumberString + PrintConst.NL);

                    receipt.Append(PrintConst.INVOICEIDSTR);
                    string transIdString = payment.TransactionResponse.InvoiceNo == null ? "" : payment.TransactionResponse.InvoiceNo;
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.INVOICEIDSTR.Length + transIdString.Length), ' ');
                    receipt.Append(transIdString + PrintConst.NL);


                    receipt.Append(PrintConst.SUBTOTALSTR);
                    string subtotalString = sub.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.SUBTOTALSTR.Length + subtotalString.Length)), ' ');
                    receipt.Append(subtotalString + PrintConst.NL);


                    if (tip != 0)
                    {
                        receipt.Append(PrintConst.TIPSTR);
                        string tipString = tip.ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.TIPSTR.Length + tipString.Length), ' ');
                        receipt.Append(tipString + PrintConst.NL);
                    }

                    receipt.Append(PrintConst.TOTALSTR);
                    string totalString = (sub + tip).ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.TOTALSTR.Length + totalString.Length)), ' ');
                    receipt.Append(totalString + PrintConst.NL);

                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                }

                receipt.Append(PrintConst.GTOTALTRANSSTR);
                string grandTotal = count.ToString();
                Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.GTOTALTRANSSTR.Length + grandTotal.Length)), ' ');
                receipt.Append(grandTotal + PrintConst.NL);

                receipt.Append(PrintConst.GTOTALPRODSTR);
                grandTotal = grandSub.ToString("c");
                Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.GTOTALPRODSTR.Length + grandTotal.Length)), ' ');
                receipt.Append(grandTotal + PrintConst.NL);

                receipt.Append(PrintConst.GTOTALTIPSTR);
                grandTotal = grandTip.ToString("c");
                Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.GTOTALTIPSTR.Length + grandTotal.Length)), ' ');
                receipt.Append(grandTotal + PrintConst.NL);

                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                receipt.Append(PrintConst.GTOTALPROCSTR);
                grandTotal = (grandTip + grandSub).ToString("c");
                Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.GTOTALPROCSTR.Length + grandTotal.Length)), ' ');
                receipt.Append(grandTotal + PrintConst.NL);

                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                System.Threading.Tasks.Task.Factory.StartNew(() => Print(printName, receipt));
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwInterface"></param>
        /// <param name="order"></param>
        /// <param name="check"></param>
        /// <param name="cardName"></param>
        /// <param name="cardNumber"></param>
        /// <returns></returns>
        public static void PrintCreditCardReceipt(
            string printName,
            ORDER order,
            CREDIT_TRANSACTION_PRINT_PACKET payment,
            int checkNo
            )
        {
            try
            {
                StringBuilder receipt = new StringBuilder();
                Helpers.Init(receipt);
                receipt.Append(PrintConst.PRINTLOGO);
                Helpers.AppendPayHeader(receipt, order, (checkNo + 1).ToString());

                receipt.Append(PrintConst.BOLD);
                receipt.Append(PrintConst.OCEANSIDE_TRANSIDSTR);
                string transactionIdStr = payment.Transaction.Id.ToString();
                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                    (PrintConst.OCEANSIDE_TRANSIDSTR.Length + transactionIdStr.Length), ' ');
                receipt.Append(transactionIdStr + PrintConst.NL);


                receipt.Append(PrintConst.OCEANSIDE_INVOICEIDSTR);
                string invoiceIdStr = order.Id.ToString();
                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                    (PrintConst.OCEANSIDE_INVOICEIDSTR.Length + invoiceIdStr.Length), ' ');
                receipt.Append(invoiceIdStr + PrintConst.NL + PrintConst.NL);

                if (!string.IsNullOrEmpty(payment.Transaction.CustomerName))
                {
                    string trimName = payment.Transaction.CustomerName.Trim();
                    receipt.Append(PrintConst.CUSTNAME);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.CUSTNAME.Length + trimName.Length), ' ');
                    receipt.Append(trimName + PrintConst.NL);
                }
                else
                {
                    string trimName = "N/A";
                    receipt.Append(PrintConst.CUSTNAME);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.CUSTNAME.Length + trimName.Length), ' ');
                    receipt.Append(trimName + PrintConst.NL);
                }

                if (payment.Transaction.TransactionType == TRANSACTION.CONST_PAY_GIFT)
                {
                    receipt.Append(PrintConst.TYPESTR);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                        (PrintConst.TYPESTR.Length + "Gift".Length), ' ');
                    receipt.Append("Gift" + PrintConst.NL);
                }
                else if (payment.TransactionResponse.CardType != null)
                {
                    receipt.Append(PrintConst.TYPESTR);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                        (PrintConst.TYPESTR.Length + payment.TransactionResponse.CardType.Length), ' ');
                    receipt.Append(payment.TransactionResponse.CardType + PrintConst.NL);
                }

                if (payment.TransactionResponse.Card4 != null)
                {
                    receipt.Append(PrintConst.CARDNUMSTR);
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                        (payment.TransactionResponse.Card4.Length + PrintConst.CARDXSTR.Length + PrintConst.CARDNUMSTR.Length), ' ');
                    receipt.Append(PrintConst.CARDXSTR + payment.TransactionResponse.Card4 + PrintConst.NL);
                }

                if (payment.TransactionResponse.CmdStatus != null)
                {
                    receipt.Append(PrintConst.AUTHSTR);
                    string authString = payment.TransactionResponse.CmdStatus;
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.AUTHSTR.Length + authString.Length), ' ');
                    receipt.Append(authString + PrintConst.NL + PrintConst.NL);
                }


                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');


                receipt.Append(PrintConst.PAIDSTR);
                string paidStr = payment.Transaction.Base.ToString("c");
                Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.PAIDSTR.Length + paidStr.Length)), ' ');
                receipt.Append(paidStr + PrintConst.NL);


                if (payment.Transaction.TransactionType == TRANSACTION.CONST_PAY_GIFT && payment.TransactionResponse.Balance != null)
                {
                    receipt.Append(PrintConst.GCBALANCE);
                    string gcbalance = "$" + payment.TransactionResponse.Balance;
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.GCBALANCE.Length + gcbalance.Length)), ' ');
                    receipt.Append(gcbalance + PrintConst.NL);
                }

                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                receipt.Append(PrintConst.NL);

                SYSCONFIG sysconfig = SYSCONFIG.Get(SHIFT.GlobalContext);
                if (sysconfig != null)
                {
                    if (sysconfig.CanAcceptTips)
                    {
                        if (payment.Transaction.TransactionType == TRANSACTION.CONST_PAY_CREDIT)
                        {
                            receipt.Append(PrintConst.TIPSTR);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH -
                                (PrintConst.TIPSTR.Length + PrintConst.AMOUNTLINESTR.Length), ' ');
                            receipt.Append(PrintConst.AMOUNTLINESTR + PrintConst.NL + PrintConst.NL);

                            receipt.Append(PrintConst.TOTALSTR);
                            Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - (PrintConst.TOTALSTR.Length + PrintConst.AMOUNTLINESTR.Length), ' ');
                            receipt.Append(PrintConst.AMOUNTLINESTR + PrintConst.NL + PrintConst.NL + PrintConst.NL);

                        }
                        else if (payment.Transaction.TransactionType == TRANSACTION.CONST_PAY_GIFT)
                        {
                            receipt.Append(" *Gift Transactions Cannot Accept Tips*" + PrintConst.NL + PrintConst.NL + PrintConst.NL + PrintConst.NL);
                        }


                        ///Feed Down
                        receipt.AppendLine(Constants.NEWLINE);
                    }
                }


                if ((Payments.PaymentEngine.HighTicketAmount == null || Payments.PaymentEngine.HighTicketAmount <= 0 ||
                    Payments.PaymentEngine.HighTicketAmount >= payment.Transaction.Base))
                {
                    receipt.Append(Constants.NEWLINE);
                    ///Customer signature
                    Helpers.AddCustomerSignatureLine(receipt, PrintConst.MAX_LINE_WIDTH);
                }
                Helpers.AddCustomerFooter(receipt);

                receipt.Append(PrintConst.FEED4 + PrintConst.CUTPAPER);
                System.Threading.Tasks.Task.Factory.StartNew(() => Print(printName, receipt));
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwInterface"></param>
        /// <param name="table"></param>
        /// <param name="check"></param>
        /// <returns></returns>
        public static void PrintItemizedReceipt(Int64 localPrinterId,
            ORDER table,
            decimal autoGratuity,
            decimal subtotal,
            decimal tax,
            int checkNo,
            int equalPayCount = 0)
        {
            try
            {
                string path = PRINTER.GetPrinterPathById(localPrinterId);

                if (path != null)
                {
                    StringBuilder receipt = new StringBuilder();
                    Helpers.Init(receipt);
                    receipt.Append(PrintConst.PRINTLOGO);

                    if (equalPayCount == 0)
                    {
                        Helpers.AppendPayHeader(receipt, table, (checkNo + 1).ToString());
                    }
                    else
                    {
                        Helpers.AppendPayHeader(receipt, table, (checkNo + 1).ToString() + "," + equalPayCount + " Equal Payments");
                    }

                    List<SALE> sales = table.GetChecksSales(checkNo).ToList();
                    foreach (SALE product in sales)
                    {
                        string pString = "";
                        ///Contains modifiers
                        if (product.IsExceptionModifier || product.IsForcedModifier)
                        {
                            Helpers.PaddWithChar(receipt,
                                Constants.CONST_MAX_RECEIPT_QUANTITY_ORDERED_WIDTH +
                                1 + Constants.CONST_TOTAL_PRINTER_NOTE_WIDTH + 1, ' ');

                            receipt.Append(product.ProductName);

                            int spaces = PrintConst.MAX_LINE_WIDTH - (product.ProductName.Length + (product.ActualPrice.ToString("c") + " Ea").Length +
                                Constants.CONST_MAX_RECEIPT_QUANTITY_ORDERED_WIDTH + 1 + Constants.CONST_TOTAL_PRINTER_NOTE_WIDTH + 1);

                            Helpers.PaddWithChar(receipt, spaces, ' ');

                            receipt.Append((product.ActualPrice.ToString("c") + " Ea") + PrintConst.NL);
                        }
                        else
                        {
                            pString = product.CountOrdered.ToString();
                            Helpers.PaddWithChar(ref pString, (Constants.CONST_MAX_RECEIPT_QUANTITY_ORDERED_WIDTH + 1
                                + Constants.CONST_TOTAL_PRINTER_NOTE_WIDTH + 1) - pString.Length, ' ');
                            pString += product.ProductName + ' ';

                            int spaces = PrintConst.MAX_LINE_WIDTH - (pString.Length + (product.ActualPrice.ToString("c") + " Ea").Length);
                            Helpers.PaddWithChar(ref pString, spaces, ' ');
                            receipt.Append(pString + (product.ActualPrice.ToString("c") + " Ea") + PrintConst.NL);
                        }
                    }


                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                    List<TRANSACTION> checksTactions = table.GetChecksTransactions(checkNo).ToList();
                    List<ORDER.DiscountDisplay> discounts = table.GetChecksDiscounts(table, checkNo, SHIFT.GlobalContext);
                    AppendCurrentCredits(discounts, receipt);

                    ///Used in equal payments.
                    string prefix = "";

                    if (equalPayCount > 1)
                    {
                        prefix = "1/" + equalPayCount + " ";
                        receipt.Append(PrintConst.EQUALPAYSTR);
                        string equalPayStr = equalPayCount.ToString();
                        Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (PrintConst.EQUALPAYSTR.Length + equalPayStr.Length)), ' ');
                        receipt.Append(equalPayStr + PrintConst.NL);
                    }
                    receipt.Append(prefix + PrintConst.SUBTOTALSTR);
                    string subtotalString = subtotal.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - ((prefix + PrintConst.SUBTOTALSTR).Length + subtotalString.Length)), ' ');
                    receipt.Append(subtotalString + PrintConst.NL);

                    receipt.Append(prefix + PrintConst.TAXSTR);
                    string taxString = tax.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - ((prefix + PrintConst.TAXSTR).Length + taxString.Length)), ' ');
                    receipt.Append(taxString + PrintConst.NL);


                    if (autoGratuity != 0M)
                    {
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        receipt.Append(prefix + PrintConst.GRATUITY);

                        string tipString = autoGratuity.ToString("c");
                        Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH - ((prefix + PrintConst.GRATUITY).Length + tipString.Length), ' ');
                        receipt.Append(tipString + PrintConst.NL);
                    }
                    Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');

                    receipt.Append(prefix + PrintConst.TOTALSTR);
                    string totalString = (subtotal + tax + autoGratuity).ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - ((prefix + PrintConst.TOTALSTR).Length + totalString.Length)), ' ');
                    receipt.Append(totalString + PrintConst.NL);

                    receipt.Append(PrintConst.FEED5 + PrintConst.CUTPAPER);
                    System.Threading.Tasks.Task.Factory.StartNew(() => Print(path, receipt));
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="check"></param>
        private static void AppendCurrentCredits(List<ORDER.DiscountDisplay> transactions, StringBuilder receipt)
        {
            bool hadCredits = false;
            foreach (ORDER.DiscountDisplay credit in transactions)
            {
                COMP_ACCOUNT promo =
                    SHIFT.GlobalContext.COMP_ACCOUNTS.Where(ca => ca.Id == credit.DiscountId && ca.IsPromo).FirstOrDefault();
                if (promo != null)
                {
                    hadCredits = true;
                    receipt.Append(credit.Type);
                    string creditAmount = "-" + credit.Amount.ToString("c");
                    Helpers.PaddWithChar(receipt, (PrintConst.MAX_LINE_WIDTH - (credit.Type.Length + creditAmount.Length)), ' ');
                    receipt.Append(creditAmount + PrintConst.NL);
                }
            }

            if (hadCredits)
            {
                Helpers.PaddWithChar(receipt, PrintConst.MAX_LINE_WIDTH, '-');
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="callbackObj"></param>
        /// <returns></returns>
        public static void PrintDispatchedReceipt(ORDER order)
        {
            try
            {
                List<PrintObject> printersList = GetPrinterGroupingsNeededForOrder(order);

                if (printersList.Count != 0)
                {
                    ///In theory every product that belongs at a product group can have it's own remote printer.  As such,
                    ///we need to build a receipt header for every printer we are sending data to.
                    foreach (PrintObject po in printersList)
                    {
                        po.Receipt.Append(PrintConst.DBLHIGH_DBLWIDE_OFF);
                        Helpers.Init(po.Receipt);
                        Helpers.AppendHeader(po.Receipt, order, null, false);
                        po.Receipt.Append(PrintConst.DBLHIGH_DBLWIDE_ON);
                        po.Receipt.Append(PrintConst.BOLD);
                    }
                    for (int seat = 0; seat < order.GuestCount; seat++)
                    {
                        string seatNo = "\n*** Seat " + (seat + 1).ToString() + " ***";

                        List<SALE> seatsSales = null;
                        try
                        {
                            seatsSales = SHIFT.SelectedOrder.GetSeatsSales(seat).ToList();
                        }
                        catch (Exception e)
                        {
                            Logging.LogException(e);
                        }

                        if (seatsSales != null)
                        {
                            foreach (SALE seatsSale in seatsSales)
                            {
                                if (seatsSale.CountPendingKitchenSend != 0 &&
                                    seatsSale.OnHold == false &&
                                    seatsSale.PrinterGroupingId != null)
                                {
                                    PrintObject po = GetPrinterObject((long)seatsSale.PrinterGroupingId, printersList);
                                    if (po != null)
                                    {
                                        if (!po.SeatIsAppended)
                                        {
                                            po.Receipt.Append(PrintConst.BLACK);
                                            po.Receipt.AppendLine(seatNo);
                                            po.SeatIsAppended = true;
                                        }

                                        string pString = "";
                                        ///Contains modifiers
                                        if (seatsSale.IsForcedModifier || seatsSale.IsExceptionModifier)
                                        {
                                            string excString = "";

                                            ///Space over to the next area where we apply the printer note
                                            Helpers.PaddWithChar(ref excString,
                                                (Constants.CONST_MAX_RECEIPT_QUANTITY_ORDERED_WIDTH + 1), ' ');

                                            ///Apply the printer note
                                            excString += seatsSale.NoteForPrint;

                                            ///Space over to where you add the product name.
                                            Helpers.PaddWithChar(ref excString,
                                                (Constants.CONST_TOTAL_PRINTER_NOTE_WIDTH + 1) - seatsSale.NoteForPrint.Length, ' ');

                                            ///Add the product name
                                            excString += seatsSale.ProductName;

                                            ///Add it to the receipt.
                                            po.Receipt.Append(PrintConst.RED + excString + PrintConst.NL);
                                        }
                                        else
                                        {
                                            ///Add the line number
                                            pString = seatsSale.CountPendingKitchenSend.ToString();

                                            ///Space over to the next area where we apply the printer note
                                            Helpers.PaddWithChar(ref pString,
                                                (Constants.CONST_MAX_RECEIPT_QUANTITY_ORDERED_WIDTH + 1) - pString.Length, ' ');

                                            ///Apply the printer note
                                            pString += seatsSale.NoteForPrint;

                                            ///Space over to where you add the product name.
                                            Helpers.PaddWithChar(ref pString,
                                                (Constants.CONST_TOTAL_PRINTER_NOTE_WIDTH + 1) - seatsSale.NoteForPrint.Length, ' ');

                                            ///Add the product name
                                            pString += seatsSale.ProductName + ' ';

                                            ///Add it to the receipt.
                                            po.Receipt.Append(PrintConst.BLACK + PrintConst.NL + pString + PrintConst.NL);
                                        }
                                        seatsSale.PrintJobId = po.JobId;
                                    }
                                    else
                                    {
                                        Logging.LogMessage("The print object was null for PG " + seatsSale.PrinterGroupingId + ".  The product was a " + seatsSale.ProductName + " and its see server value was set to " + seatsSale.IsSeeServer + " with a price of " + seatsSale.ActualPrice + ".  The sale id is " + seatsSale.Id + ".");

                                        if (seatsSale.ORDER != null)
                                        {
                                            Logging.LogMessage("The seats sale orderId was " + seatsSale.ORDER.Id + ".");
                                        }
                                        else
                                        {
                                            Logging.LogMessage("The seats sale had a null order");
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            Logging.LogMessage("Seats sales is empty.");
                        }
                        ///Now we neeed to clear all of the seat flags.
                        foreach (PrintObject po in printersList)
                        {
                            po.SeatIsAppended = false;
                        }
                    }
                    ///Now finalize every receipt group and print
                    foreach (PrintObject po in printersList)
                    {
                        po.Receipt.Append(PrintConst.DBLHIGH_DBLWIDE_OFF);
                        po.Receipt.Append(PrintConst.NORMAL);
                        po.Receipt.Append(PrintConst.BLACK);
                        ///Finalize the end of the receipt including the paper cut.
                        Helpers.PaddWithChar(po.Receipt, PrintConst.MAX_LINE_WIDTH, '-');
                        po.Receipt.Append(PrintConst.CUTPAPER);

                        PRINTER_GROUP pg = PRINTER_GROUP.GetPrinterGroupById(po.PrinterGroupingId);
                        if (pg != null)
                        {
                            if (pg.PRINTERS.Count() != 0)
                            {
                                List<string> printers = GetNonDeletedPrinters(pg);
                                if (printers != null)
                                {
                                    foreach (string printer in printers)
                                    {
                                        Print(printer, po.Receipt);

                                        ///This thread below caused bigtime issues!  There was a threading bug related to doing 
                                        ///this.  Never had time to look into it so called Print sync above.
                                        //System.Threading.Tasks.Task.Factory.StartNew(() => Print(printer, po.Receipt));
                                    }
                                }
                            }
                        }
                        else
                        {
                            Logging.LogMessage("The printer group was null for " + po.PrinterGroupingId);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PRINTSPOOL_THREAD_START_ERROR, ex);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="pg"></param>
        /// <returns></returns>
        static List<string> GetNonDeletedPrinters(PRINTER_GROUP pg)
        {
            List<string> paths = null;

            if (pg != null)
            {
                var q = from P in pg.PRINTERS where P.IsDeleted == false select P.Path;

                if (q.Any())
                {
                    paths = q.ToList();
                }
            }
            return paths;
        }
    }
}
